using System;
using System.Diagnostics;
using System.Reflection;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace OfficeClip.OpenSource.Logger
{
	public class Log
	{
        public FileLog FileLog;
        public DbLog DbLog;

	    private List<Logger> LoggerList;

	    public string DefaultCategory { get; set; }

        public string DefaultUser { get; set; }

	    private Logger DefaultLogger
	    {
	        get
	        {
                return LoggerList.Find(x => x.Name == DefaultCategory);
	        }
	    }

	    public LogLevel LogLevel
	    {
	        get
	        {
	            return (LogLevel)DefaultLogger.Level;
	        }
	        set
	        {
	            DefaultLogger.Level = (int)value;
	        }
	    }

	    public bool IsCategoryExist(string category)
	    {
	        return LoggerList.Exists(x => x.Name == category);
	    }

	    public Log(LogConfig logConfig)
	    {
            Initialize(logConfig);
	    }

	    public Log()
	    {
	        LogConfig logConfig = new LogConfig();
            Initialize(logConfig);
	    }

	    public Log(string configFilePath)
	    {
	        LogConfig logConfig = LogConstants.DeserializeLogConfig(configFilePath);
            Initialize(logConfig);
	    }

       /// <summary>
		/// Initilizes the parameters
		/// </summary>
        protected void Initialize(LogConfig logConfig)
        {
            LoggerList = new List<Logger>();
            foreach (Logger logger in logConfig.Loggers)
            {
                LoggerList.Add(logger);
            }
            if (logConfig.PurgeDays == 0)
            {
                logConfig.PurgeDays = 7;
            }
            FileLog = new FileLog(logConfig);
            if (FileLog.IsEnabled)
            {
                FileLog.Initialize();
            }
            DbLog = new DbLog(logConfig);
            if (DbLog.IsEnabled)
            {
                DbLog.Initialize();
            }
        }

         /// <summary>
        /// Used to find the log state from sql server security levels
        /// </summary>
        /// <param name="severity"></param>
        /// <returns></returns>
		protected LogState GetLogStateFromSqlServerSeverity(int severity)
		{
			LogState state = LogState.None; // for severity level upto 10
			switch (severity)
			{
				case 11:
				case 12:
				case 13:
				case 14:
				case 15:
				case 16:
				case 17:
				case 18:
					state = LogState.Error;
					break;
				case 19:
				case 20:
				case 21:
				case 22:
				case 23:
				case 24:
				case 25:
					state = LogState.FatalError;
					break;
			}
			return state;
		}

        //public string FilterStackTrace(StackTrace stackTrace)
        //{
        //StringBuilder stringBuilder = new StringBuilder();
        //using (StringReader reader = new StringReader(stackTrace.ToString()))
        //{
        //    string line;
        //    while ((line = reader.ReadLine()) != null)
        //    {
        //        //if (line.Contains("OfficeClip."))
        //        //{
        //            stringBuilder.AppendLine(line);
        //        //}
        //    }
        //}
        //return stringBuilder.ToString();
        //}

#region Write Methods

		public void WriteSqlLog(int lineNum, int errorClass, int errorNum, string str, string user="", string category="", string custom = "")
		{
			LogState state = GetLogStateFromSqlServerSeverity(errorClass);
			const string topic = "Sql Server";
			string description = string.Format(
			   "Line#: {0}, Class: {1}, Number: {2}: {3}", lineNum, errorClass, errorNum, str
			);
            StackTrace callStack = new StackTrace(1, true);
		    string stackTrace = (
                                    (state == LogState.Error) ||
                                    (state == LogState.Debug) ||
		                            (state == LogState.FatalError))
		        ? "<br/>" + callStack.ToString()
		        : string.Empty;
		    Write(
                state,
                topic,
                string.Format(
                "{0}{1}",
                description,
                stackTrace),
                user,
                category,
                custom); 
		}

        public void WriteProperty(string propertyName, string propertyDescription, string user = "", string category = "", string custom = "")
		{
			Write(LogState.Property, propertyName, propertyDescription, user, category, custom);
		}

		public void WriteFunction(
            string functionName,
		    string arg1, 
            string arg2, 
            string arg3,
            string argRest, 
            string user = "",
            string category = "", 
            string custom = "")
		{
			string desc = string.Format("({0}, {1}, {2}, {3})", arg1, arg2, arg3, argRest);
			Write(LogState.Function, functionName, desc, user, category, custom);
		}

        public void WriteMethod(
            string user = "", 
            string category = "",
            string custom = "",
            params object[] args)
        {
           StringBuilder sb = new StringBuilder();
            StackTrace callStack = new StackTrace(1, true);
            StackFrame callingMethodFrame = callStack.GetFrame(0);
            MethodBase callingMethod = callingMethodFrame.GetMethod();
            sb.Append(callingMethod.Name);
            sb.Append("(");
            ParameterInfo[] parameters = callingMethod.GetParameters();
            for (int i = 0; i < parameters.Length; i++)
            {
                sb.Append(parameters[i].Name);
                sb.Append("=");
                sb.Append(
                    (i < args.Length) && (args.Length > 0) ? 
                    args[i].ToString().Trim() : 
                    "???");
                sb.Append(",");
            }
            string output = sb.ToString().TrimEnd(',') + ")";
            Write(
                LogState.Method, 
                string.Format(
                    "{0}:{1}",
                    callingMethodFrame.GetFileName(),
                    callingMethodFrame.GetFileLineNumber()), 
                output,
                user,
                category,
                custom);
        }

        public void WriteEvent(string title, string description, string user = "", string category = "", string custom = "")
		{
			Write(LogState.Event, title, description, user, category, custom);
		}

        public void WriteInfo(string title, string description, string user = "", string category = "", string custom = "")
		{
			Write(LogState.Info, title, description, user, category, custom);
		}

	    private string StackInfo(LogState logState)
	    {
	        if (
                (logState != LogState.Error) && (logState != LogState.FatalError) && (logState != LogState.Debug))
	        {
	            return string.Empty;
	        }
	        StackTrace callStack = new StackTrace(
                1,
                true);
	        return callStack.ToString();
	    }

        public void WriteDebug(string title, string description, string user = "", string category = "", string custom = "")
		{
		    Write(
                LogState.Debug,
                title,
		        description,
                user,
                category,
                custom);
		}

	    public void WriteError(
	        string title,
            string description, 
            string user = "",
            string category = "", 
            string custom = "")
	    {
	        Write(
                LogState.Error,
                title,
	            description,
                user, 
                category, 
                custom);
	    }

        public void WriteFatalError(string title, string description, string user = "", string category = "", string custom = "")
		{
            Write(
                LogState.FatalError,
                title,
                description,
                user,
                category,
                custom);
        }

        public void WriteWarning(string title, string description, string user = "", string category = "", string custom = "")
		{
			Write(LogState.Warning, title, description, user, category, custom);
		}

        public void WritePass(string title, string description, string user = "", string category = "", string custom = "")
		{
			Write(LogState.Pass, title, description, user, category, custom);
		}

        public void WriteSubTitle(string title, string description, string user = "", string category = "", string custom = "")
		{
			Write(LogState.SubTitle, title, description, user, category, custom);
		}

#endregion Write Methods

		public void Write(LogState state, string topic, string description, string user = "", string category="", string custom="" )
		{
		    string categoryValue = category;
		    Logger logger = DefaultLogger;
		    if (logger != null)
		    {               
		        if (
                    (logger.Name == categoryValue) &&
                    (logger.Level < (int) LogConstants.GetLogLevel(state)))
		        {
		            return;
		        }
		        categoryValue = logger.Name;
		    }
		    if (user == string.Empty)
		    {
		        user = DefaultUser;
		    }
		    if (FileLog.IsEnabled)
		    {
		        FileLog.WriteLog(
		                         state,
                                 StackInfo(state),
		                         topic,
		                         description,
                                 categoryValue,
                                 user,
                                 custom);
		    }
            if (DbLog.IsEnabled)
            {
                DbLog.WriteLog(
                                 state,
                                 StackInfo(state),
                                 topic,
                                 description,
                                 user,
                                 categoryValue,
                                 custom);
            }
		}

	}
}
